package mi.payment.utils.transaction;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

import mi.payment.settings.NetworkDataOperations;
import mi.payment.utils.ThreadPoolManager;
import mi.payment.utils.iso8583.Utils;
import sunmi.payment.ui.dialog.LoadDialog;


public abstract class BaseCountDownTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
    private static final String TAG = "BaseCountDownTask";
    private static final int DEFAULT_TIMEOUT = 60;//默认倒计时时间，60s
    private static int taskCount = 1;
    private final int id = taskCount++;

    @SuppressLint("StaticFieldLeak")
    private static LoadDialog loadDialog;//Dlg设置成static，方便子修改message
    private boolean isDialogDismissed = false; //dialog 是否已被dismiss过

    private CyclicBarrier barrier = new CyclicBarrier(2);//计数栅栏
    private CountDownTask countDownTask;
    private int timeoutCount = -1;  // 计数次数，单位为秒
    private Handler mainHandler = new MainHandler(this);    // 用于执行超时任务
    private Runnable timeoutTask;       // 超时时执行的任务
    private volatile Thread runner;     //工作线程
    private volatile boolean finished;  // 任务是否完成
    private volatile boolean isTaskTimeout;   //任务是否超时
    protected volatile boolean isTaskSucceed; //任务是否成功
    private volatile Result taskResult;  //任务返回值


    private static class MainHandler extends Handler {
        private static final int PROGRESS_UPDATE = 1;//进度更新
        private static final int TASK_FINISHED = 2;//任务结束
        private static final int TASK_TIMEOUT = 3;//任务超时

        private BaseCountDownTask task;

        MainHandler(BaseCountDownTask transTask) {
            super(Looper.getMainLooper());
            task = transTask;
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case PROGRESS_UPDATE:
                    task.handleUpdateProgress(msg.arg1);
                    break;
                case TASK_FINISHED:
                    task.dismissProgressDlg();
                    break;
                case TASK_TIMEOUT:
                    task.handleTimeout();
                    break;
            }
        }
    }

    private static class CountDownTask implements Runnable {
        private BaseCountDownTask task;
        private volatile boolean finish;

        private CountDownTask(BaseCountDownTask task) {
            this.task = task;
        }

        @Override
        public void run() {
            try {
                task.barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            int count = task.timeoutCount;
            try {
                while (!Thread.interrupted() && !finish) {
                    Thread.sleep(1000);
                    //任务正常结束
                    if (task.finished) {
                        task.mainHandler.obtainMessage(MainHandler.TASK_FINISHED).sendToTarget();
                        break;
                    }
                    //任务超时
                    if (--count == 0) {
                        task.isTaskTimeout = true;
                        task.cancel(true);
                        interruptTask();
                        task.mainHandler.obtainMessage(MainHandler.TASK_TIMEOUT).sendToTarget();
                        break;
                    }
                    //更新进度
                    task.mainHandler.obtainMessage(MainHandler.PROGRESS_UPDATE, count, 0).sendToTarget();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                task.mainHandler.obtainMessage(MainHandler.TASK_FINISHED).sendToTarget();
            }
        }

        /**
         * 中断计时任务
         */
        private void stopSelf() {
            finish = true;
        }


        /**
         * 中断工作线程，每10ms尝试一次，直至线程
         * 被成功中断或者任务成功完成
         */
        private void interruptTask() {
            int index = 1;
            try {
                while (!task.finished) {
                    Log.e(TAG, task.getName() + ":第" + (index++) + "次被中断");
                    task.runner.interrupt();
                    Thread.sleep(10);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置超时时间,单位为秒,此方法在execute()方法调用才有效
     */
    public void setTaskTimeout(int timeout) {
        timeoutCount = timeout;
    }

    /**
     * 设置超时时间,单位为秒,
     */
    public int getTaskTimeout() {
        return timeoutCount;
    }

    /**
     * 设置超时任务
     */
    public void setTimeoutTask(Runnable runnable) {
        timeoutTask = runnable;
    }

    /**
     * 设置倒计时对话框
     */
    public void setLoadDialog(LoadDialog dlg) {
        loadDialog = dlg;
    }

    /**
     * 返回倒计时对话框对象
     */
    public LoadDialog getLoadDialog() {
        return loadDialog;
    }

    private void initProgressDlg() {
        if (timeoutCount > 0) {
            handleUpdateProgress(timeoutCount);
        }
        showProgressDlg();
    }

    private void showProgressDlg() {
        if (loadDialog != null) {
            loadDialog.show();
        }
    }

    private void dismissProgressDlg() {
        if (loadDialog != null && !isDialogDismissed) {
            loadDialog.dismiss();
            loadDialog = null;
            isDialogDismissed = true;
        }
    }

    private void handleUpdateProgress(int progress) {
        if (loadDialog != null) {
            loadDialog.updateProgress(progress);
        }
    }

    private void handleTimeout() {
        dismissProgressDlg();
        if (isTaskSucceed) {
            //任务执行成功
            onPostExecuteImpl(taskResult);
        } else {
            //任务因超时而失败
            onTaskTimeoutImpl();
            if (timeoutTask != null) {
                timeoutTask.run();
            }
        }
    }

    private void startCountDownTask() {
        countDownTask = new CountDownTask(this);
        ThreadPoolManager.executeInCachePool(countDownTask);
        try {
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    private String getName() {
        Class cls = getClass();
        String name = cls.getSimpleName();
        while (TextUtils.isEmpty(name)) {
            cls = cls.getSuperclass();
            name = cls.getSimpleName();
        }
        return name + "-" + id;
    }

    /**
     * 仅供基类调用的方法，子类请调用onPreExecuteImpl()方法
     */
    @Deprecated
    @Override
    protected final void onPreExecute() {
        super.onPreExecute();
        onPreExecuteImpl();
        initTimeoutCount();
        initProgressDlg();
    }

    private void initTimeoutCount() {
        if (timeoutCount <= 0) {
            setTaskTimeout(getDefaultCommunicationTimeout());
        }
    }

    private int getDefaultCommunicationTimeout() {
        String timeout = NetworkDataOperations.getInstance().getNetworkParamSettings().getCommunicationTimeout();
        if (!TextUtils.isEmpty(timeout) && Utils.isNumeric(timeout)) {
            return Integer.parseInt(timeout);
        }
        return DEFAULT_TIMEOUT;
    }

    /**
     * 仅供基类调用的方法，子类请调用doInBackgroundImpl(Params... params)方法
     */
    @Deprecated
    @Override
    protected final Result doInBackground(Params... params) {
        startCountDownTask();
        runner = Thread.currentThread();
        taskResult = doInBackgroundImpl(params);
        finished = true;
        countDownTask.stopSelf();
        return taskResult;
    }

    /**
     * 仅供基类调用的方法，子类请调用onPostExecuteImpl(Result result)方法
     */
    @Deprecated
    @Override
    protected final void onPostExecute(Result result) {
        super.onPostExecute(result);
        dismissProgressDlg();//这里主动dismiss对话框，防止onPostExecute在TASK_FINISHED之前执行
        onPostExecuteImpl(result);
    }

    /**
     * 仅供基类调用的方法，子类请勿调用
     */
    @Deprecated
    @Override
    protected final void onCancelled() {
    }


    /**
     * 仅供基类调用的方法，子类请勿调用
     */
    @Deprecated
    @Override
    protected final void onCancelled(Result result) {
    }

    /**
     * <pre>
     * 类似onPreExecute,子类可重写此方法
     * 执行线程：UI线程执行
     *  </pre>
     */
    protected void onPreExecuteImpl() {
    }

    /**
     * <pre> 类似doInBackground,子类必须重写此方法
     * 执行线程：后台线程
     * </pre>
     */
    protected abstract Result doInBackgroundImpl(Params... params);

    /**
     * <pre>
     * 类似onPostExecute,子类可重写此方法
     * 执行线程：UI线程
     * </pre>
     */
    protected void onPostExecuteImpl(Result result) {

    }

    /**
     * <pre>
     * 返回任务超时标识,true:超时,false:未超时
     * 执行线程：调用本方法的线程
     * </pre>
     */
    protected boolean isTaskTimeout() {
        return isTaskTimeout;
    }

    /**
     * <pre>
     * 任务超时回调，子类可重写此方法，效果与setTimeoutTask(Runnable r)相同
     * 执行线程：UI线程
     * </pre>
     */
    protected void onTaskTimeoutImpl() {

    }

}
